﻿/* 2013/1/10 */
using System.Collections.Generic;
using System.ComponentModel;

namespace Cosmos.Media.Play
{
    /// <summary>
    /// Represents a play tree node that contains play items and sub-nodes.
    /// </summary>
    public class PlayTreeNode : IPlayEntity
    {
        private string _name;

        private PlayTreeNode _parentNode;
        private PlayTreeNodeCollection _nodes;
        private PlayList _list;

        private PlayTagCollection _tags;
        private PlayAttributeCollection _attributes;

        /// <summary>
        /// Initializes a new instance of PlayTreeNode class.
        /// </summary>
        private PlayTreeNode()
        {
            _list = new PlayList(this);
            _nodes = new PlayTreeNodeCollection(this);
            _tags = new PlayTagCollection(this);
            _attributes = new PlayAttributeCollection(this);
        }

        /// <summary>
        /// Initializes a new instance of PlayTreeNode class.
        /// </summary>
        /// <param name="name">Name of the tree node.</param>
        public PlayTreeNode(string name)
            : this()
        {
            _name = name;
        }

        /// <summary>
        /// Initializes a new instance of PlayTreeNode class that contains elements copied from the specified collection.
        /// </summary>
        /// <param name="name">Name of the tree node.</param>
        /// <param name="items"></param>
        public PlayTreeNode(string name, IEnumerable<PlayListItem> items)
            : this()
        {
            _name = name;
            foreach (PlayListItem anItem in items)
            {
                _list.Items.Add(anItem);
            }
        }

        /// <summary>
        /// Copies all play items to a specified play list.
        /// </summary>
        /// <param name="list">The play list that is the destination of the items copied from this node.</param>
        public void CopyTo(PlayList list)
        {
            foreach (PlayListItem anItem in _list.Items)
            {
                list.Items.Add(new PlayListItem(anItem.Name, anItem.Path));
            }

            foreach (PlayTreeNode aNode in _nodes)
            {
                aNode.CopyTo(list);
            }
        }

        /// <summary>
        /// Copies all play items to a play list.
        /// </summary>
        /// <returns>A play list containing all items of this node and sub-nodes.</returns>
        public PlayList ToPlayList()
        {
            PlayList list = new PlayList();
            CopyTo(list);
            return list;
        }

        /// <summary>
        /// Copies all play items to a play tree node.
        /// </summary>
        /// <returns>A play tree node containing all items of this node and sub-nodes.</returns>
        public PlayTreeNode ToPlayTreeNode()
        {
            PlayTreeNode node = new PlayTreeNode();
            CopyTo(node.List);
            return node;
        }

        private List<PlayAttribute> GetInheritedAttributes()
        {
            LinkedList<PlayAttribute> inheritedAttributeLinkedList = new LinkedList<PlayAttribute>();
            HashSet<string> singleAttributeNames = new HashSet<string>();
            HashSet<string> multipleAttributeNames = new HashSet<string>();

            foreach (PlayAttribute anAttribute in _attributes)
            {
                if (anAttribute.AllowMultiple)
                {
                    multipleAttributeNames.Add(anAttribute.Name);
                }
                else
                {
                    singleAttributeNames.Add(anAttribute.Name);
                }
            }

            PlayTreeNode parentNode = ParentNode;
            while (parentNode != null)
            {
                LinkedListNode<PlayAttribute> addedListNode = null;
                foreach (PlayAttribute anAttribute in parentNode.Attributes)
                {
                    if (anAttribute.Inherited)
                    {
                        if (anAttribute.AllowMultiple
                            && !singleAttributeNames.Contains(anAttribute.Name))
                        {
                            multipleAttributeNames.Add(anAttribute.Name);

                            if (addedListNode == null)
                            {
                                addedListNode = inheritedAttributeLinkedList.AddFirst(anAttribute);
                            }
                            else
                            {
                                addedListNode = inheritedAttributeLinkedList.AddAfter(addedListNode, anAttribute);
                            }
                        }
                        else if (!anAttribute.AllowMultiple
                            && !multipleAttributeNames.Contains(anAttribute.Name)
                            && !singleAttributeNames.Contains(anAttribute.Name))
                        {
                            singleAttributeNames.Add(anAttribute.Name);
                            
                            if (addedListNode == null)
                            {
                                addedListNode = inheritedAttributeLinkedList.AddFirst(anAttribute);
                            }
                            else
                            {
                                addedListNode = inheritedAttributeLinkedList.AddAfter(addedListNode, anAttribute);
                            }
                        }
                    }
                }

                parentNode = parentNode.ParentNode;
            }

            List<PlayAttribute> inheritedAttributeList = new List<PlayAttribute>(inheritedAttributeLinkedList.Count);
            foreach (PlayAttribute anAttribute in inheritedAttributeLinkedList)
            {
                inheritedAttributeList.Add(anAttribute);
            }
            return inheritedAttributeList;
        }

        /// <summary>
        /// Gets parent node of this play tree node.
        /// </summary>
        public PlayTreeNode ParentNode
        {
            get
            {
                return _parentNode;
            }

            internal set
            {
                _parentNode = value;
            }
        }

        /// <summary>
        /// Gets or sets name of this tree node.
        /// </summary>
        public string Name
        {
            get
            {
                return _name;
            }

            set
            {
                _name = value;
            }
        }

        /// <summary>
        /// Gets a list containing all items in this tree node. 
        /// The items contained in the sub-nodes will not be contained.
        /// </summary>
        public PlayList List
        {
            get
            {
                return _list;
            }

            protected set
            {
                if (value != null)
                    _list = value;
            }
        }

        /// <summary>
        /// Gets a collection containing all sub-nodes in this tree node.
        /// </summary>
        public PlayTreeNodeCollection Nodes
        {
            get
            {
                return _nodes;
            }

            protected set
            {
                if (value != null)
                    _nodes = value;
            }
        }

        /// <summary>
        /// Gets collection that contains tags of this play tree node.
        /// </summary>
        public PlayTagCollection Tags
        {
            get
            {
                return _tags;
            }

            protected set
            {
                if (value != null)
                    _tags = value;
            }
        }

        /// <summary>
        /// Gets a collection that contains attributes of this play tree node.
        /// </summary>
        public PlayAttributeCollection Attributes
        {
            get
            {
                return _attributes;
            }

            protected set
            {
                if (value != null)
                    _attributes = value;
            }
        }

        /// <summary>
        /// Gets inherited attributes from all parent nodes.
        /// </summary>
        public IList<PlayAttribute> InheritedAttributes
        {
            get
            {
                return GetInheritedAttributes();
            }
        }
    }
}
